package com.pd.service;

import com.pd.rpc.BizEnum;
import com.pd.rpc.SeqGeneration;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author: dong peng
 * @Date: 2018/3/6 17:54
 * @Description:  根据规则生成唯一序列号   时间戳+标识符+10位数字
 */

public class SeqGenerationImpl implements SeqGeneration {

    private static int count = 0;

    private final static long MACHINE_ID = 5;   //机器标识
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数

    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

    private long sequence = 0L; //序列号
    private long lastStmp = -1L;//上一次时间戳


    private String fmtDate(long currStmp) {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        return format.format(new Date());
    }

    /**
     * 业务流水号(唯一标示一笔业务)
     * 由业务前缀(2字符,参见SeqNumGeneration.BizEnum)+日期时间(yyyyMMddHHmmss)+1位机器号+流水号(5位数字)组成
     *
     * @return
     */
    public synchronized String generateBizSeqNo(BizEnum constant){

        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            //相同毫秒内，序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒内，序列号置为0
            sequence = 0L;
        }

        String dateStr = fmtDate(currStmp);
        StringBuffer sb = new StringBuffer();
        sb.append(constant.name()).append(dateStr).append(MACHINE_ID);
//        String len = String.valueOf(sequence);
//        while (len.length() <= 3) {
//            sb.append(0);
//        }
        sb.append(sequence);

        lastStmp = currStmp;
        return sb.toString();

    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }

    private long getNewstmp() {
        return System.currentTimeMillis();
    }

    @Override
    public String nextId(BizEnum bizCode) {
        return generateBizSeqNo(BizEnum.CM);
    }

}
